package com.hxm.meizi.http;

import com.hxm.meizi.app.Constants;
import com.hxm.meizi.copytoserver.DetailInfo;
import com.hxm.meizi.copytoserver.ImageInfoListener;
import com.hxm.meizi.copytoserver.ImageList;
import com.hxm.meizi.copytoserver.ImageLoadingListener;
import com.hxm.meizi.entity.EveryDay;
import com.hxm.meizi.entity.ImageInfo;
import com.hxm.meizi.entity.ImageUrl;
import com.hxm.meizi.entity.ZhuanTi;
import com.hxm.meizi.entity.ZhuanTiName;
import com.hxm.meizi.entity.ZiPaiImage;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;

import me.drakeet.multitype.Items;
import okhttp3.ResponseBody;
import rx.Observable;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Action0;
import rx.functions.Action1;
import rx.functions.Func1;
import rx.schedulers.Schedulers;

/**
 * Created by hxm on 2017/2/18.
 * Jsoup解析
 */

public class JsoupDoc {

    /**
     * 请求数据
     *
     * @param url
     * @param listener
     */
    public static void getImageList(String url, final ItemsLoadListener listener) {
        switch (url) {
            case Constants.ZI_PAI:
                parseTypeZiPai(url, listener);
                break;
            case Constants.ZHUAN_TI:
                parseTypeZhuanTi(url, listener);
                break;
            case Constants.ALL:
                parseTypeAll(url, listener);
                break;
            default:
                parseTypeOne(url, listener);
                break;
        }
    }

    /**
     * 读取输入流，得到html的二进制数据
     *
     * @param inStream
     * @return
     * @throws Exception
     */
    private static byte[] readInputStream(InputStream inStream) {
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len;
        try {
            while ((len = inStream.read(buffer)) != -1) {
                outStream.write(buffer, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (inStream != null) {
                    inStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return outStream.toByteArray();
    }

    /**
     * 获取Observable<Document>
     *
     * @param url
     * @return
     */
    private static Observable<Document> getDocument(String url, final ItemsLoadListener loadListener) {
        return HttpRequest.getInstance().getHtml(url)
                .subscribeOn(Schedulers.io())
                .doOnSubscribe(new Action0() {
                    @Override
                    public void call() {
                        loadListener.onStart();
                    }
                })
                .subscribeOn(AndroidSchedulers.mainThread())
                .map(new Func1<ResponseBody, String>() {
                    @Override
                    public String call(ResponseBody responseBody) {
                        String html = null;
                        byte[] readByte = readInputStream(responseBody.byteStream());
                        try {
                            html = new String(readByte, "utf-8");
                        } catch (UnsupportedEncodingException e) {
                            e.printStackTrace();
                        }
                        return html;
                    }
                })
                .flatMap(new Func1<String, Observable<Document>>() {
                    @Override
                    public Observable<Document> call(String s) {
                        Document document = Jsoup.parse(s);
                        return Observable.just(document);
                    }
                });
    }

    /**
     * 解析数据
     *
     * @param url
     * @param listener
     */
    private static void parseTypeOne(final String url, final ItemsLoadListener listener) {
        final Items items = new Items();
        getDocument(url, listener)
                .flatMap(new Func1<Document, Observable<Element>>() {
                    @Override
                    public Observable<Element> call(Document document) {
                        Element content = document.getElementById("content");
                        if (!url.equals(Constants.BASE_URL)) {
                            addZhuanName(document, items);
                        }
                        Elements datas = content.getElementsByTag("article");
                        return Observable.from(datas);
                    }
                })
                .map(new Func1<Element, ImageInfo>() {
                    @Override
                    public ImageInfo call(Element element) {
                        Element title = element.select("a").first();
                        String imageTitle = title.text();
                        String imageId = title.attr("href");
                        Element category = element.select("a").get(1);
                        String imageCategory = category.text();
                        Element date = element.select("span").get(1);
                        String imageDate = date.text();
                        Element times = element.select("span").get(2);
                        String viewTimes = times.text();
                        Element url = element.select("img[data-original]").first();
                        String imageUrl = url.attr("data-original");
                        ImageInfo imageInfo = new ImageInfo();
                        imageInfo.setImageId(imageId);
                        imageInfo.setTitle(imageTitle);
                        imageInfo.setCategory(imageCategory);
                        imageInfo.setDate(imageDate);
                        imageInfo.setViewTimes(viewTimes);
                        imageInfo.setImageUrl(imageUrl);
                        return imageInfo;
                    }
                })
                .map(new Func1<ImageInfo, Items>() {
                    @Override
                    public Items call(ImageInfo imageInfo) {
                        items.add(imageInfo);
                        return items;
                    }
                })
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new BaseSubscriber<Items>() {
                    @Override
                    public void onError(NetException.ResponseThrowable e) {
                        listener.onFailure(e.message);
                    }

                    @Override
                    public void onNext(Items items) {
                        listener.onSuccess(items);
                    }
                });
    }

    /**
     * 解析自拍数据
     *
     * @param url
     * @param listener
     */
    private static void parseTypeZiPai(final String url, final ItemsLoadListener listener) {
        final Items items = new Items();
        getDocument(url, listener)
                .flatMap(new Func1<Document, Observable<Element>>() {
                    @Override
                    public Observable<Element> call(Document document) {
                        Element content = document.getElementById("content");
                        if (!url.equals(Constants.BASE_URL)) {
                            addZhuanName(document, items);
                        }
                        Elements datas = content.getElementsByClass("comment");
                        return Observable.from(datas);
                    }
                })
                .map(new Func1<Element, ZiPaiImage>() {
                    @Override
                    public ZiPaiImage call(Element element) {
                        Element upTime = element.select("a").first();
                        String upload = upTime.text();
                        Element url = element.select("img").first();
                        String imageUrl = url.attr("src");
                        ZiPaiImage imageInfo = new ZiPaiImage();

                        imageInfo.setUploadTime(upload);
                        imageInfo.setUrl(imageUrl);
                        return imageInfo;
                    }
                })
                .map(new Func1<ZiPaiImage, Items>() {
                    @Override
                    public Items call(ZiPaiImage imageInfo) {
                        items.add(imageInfo);
                        return items;
                    }
                })
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new BaseSubscriber<Items>() {
                    @Override
                    public void onError(NetException.ResponseThrowable e) {
                        listener.onFailure(e.message);
                    }

                    @Override
                    public void onNext(Items items) {
                        listener.onSuccess(items);
                    }
                });
    }

    /**
     * 专题
     *
     * @param url
     * @param listener
     */
    private static void parseTypeZhuanTi(String url, final ItemsLoadListener listener) {
        final Items items = new Items();
        getDocument(url, listener)
                .flatMap(new Func1<Document, Observable<Element>>() {
                    @Override
                    public Observable<Element> call(Document document) {
                        Element content = document.getElementsByClass("place-padding").first();
                        Elements datas = content.getElementsByTag("a");
                        return Observable.from(datas);
                    }
                })
                .map(new Func1<Element, ZhuanTi>() {
                    @Override
                    public ZhuanTi call(Element element) {
                        String url = element.attr("href");
                        String name = element.text();
                        ZhuanTi zhuanti = new ZhuanTi();
                        zhuanti.setName(name);
                        zhuanti.setUrl(url);
                        return zhuanti;
                    }
                })
                .map(new Func1<ZhuanTi, Items>() {
                    @Override
                    public Items call(ZhuanTi zhuanti) {
                        items.add(zhuanti);
                        return items;
                    }
                })
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new BaseSubscriber<Items>() {
                               @Override
                               public void onError(NetException.ResponseThrowable e) {
                                   listener.onFailure(e.message);
                               }

                    @Override
                    public void onNext(Items items) {
                                   listener.onSuccess(items);
                               }
                });
    }

    /**
     * 每日更新
     *
     * @param url
     * @param listener
     */
    private static void parseTypeAll(final String url, final ItemsLoadListener listener) {
        final Items items = new Items();
        getDocument(url, listener)
                .flatMap(new Func1<Document, Observable<Element>>() {
                    @Override
                    public Observable<Element> call(Document document) {
                        Element content = document.getElementById("content");
                        if (!url.equals(Constants.BASE_URL)) {
                            addZhuanName(document, items);
                        }
                        Elements datas = content.select("a.clear");
                        return Observable.from(datas);
                    }
                })
                .map(new Func1<Element, EveryDay>() {
                    @Override
                    public EveryDay call(Element element) {
                        String url = element.attr("href");
                        Element time = element.getElementsByClass("archive-time").first();
                        String date = time.text();
                        int length = date.length();
                        String title = element.text();
                        int tLength = title.length();
                        String titleName = title.substring(length, tLength);
                        EveryDay everyDay = new EveryDay();
                        everyDay.setDate(date);
                        everyDay.setTitle(titleName);
                        everyDay.setUrl(url);
                        return everyDay;
                    }
                })
                .map(new Func1<EveryDay, Items>() {
                    @Override
                    public Items call(EveryDay everyDay) {
                        items.add(everyDay);
                        return items;
                    }
                })
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new BaseSubscriber<Items>() {
                    @Override
                    public void onError(NetException.ResponseThrowable e) {
                        listener.onFailure(e.message);
                    }

                    @Override
                    public void onNext(Items items) {
                        listener.onSuccess(items);
                    }
                });
    }

    /**
     * 分割字符串
     *
     * @param document
     * @param items
     */
    private static void addZhuanName(Element document, Items items) {
        ZhuanTiName name = new ZhuanTiName();
        Element div = document.getElementsByClass("post-info").first();
        String tag = div.text();
        int length = tag.length();
        if (length > 4) {
            String tagName = tag.substring(0, 3);
            String zhuanName = tag.substring(3, length);
            name.setTag(tagName);
            name.setName(zhuanName);
        } else {
            name.setTag("分类: ");
            name.setName(tag);
        }
        items.add(name);
    }

    /**
     * 获取图片列表
     *
     * @param url
     * @param listener
     */
    public static void getImageDetails(String url, final ItemsLoadListener listener) {
        final Items items = new Items();
        getDocument(url, listener)
                .map(new Func1<Document, Items>() {
                    @Override
                    public Items call(Document document) {
                        Element figure = document.getElementsByTag("figure").first();
                        String firstUrl = figure.getElementsByTag("img").first().attr("src");
                        int urlLength = firstUrl.length();
                        String needUrl = firstUrl.substring(0, urlLength - 6);
                        Element pageElement = document.getElementsByClass("prev-next-page").first();
                        String pageText = pageElement.text();
                        int length = pageText.length();
                        int imageNums = Integer.parseInt(pageText.substring(2, length - 1));
                        for (int i = 1; i <= imageNums; i++) {
                            if (i < 10) {
                                ImageUrl imageUrl = new ImageUrl();
                                imageUrl.setUrl(needUrl + "0" + i + ".jpg");
                                imageUrl.setId(i);
                                items.add(imageUrl);
                            } else {
                                ImageUrl imageUrl = new ImageUrl();
                                imageUrl.setUrl(needUrl + i + ".jpg");
                                imageUrl.setId(i);
                                items.add(imageUrl);
                            }
                        }
                        return items;
                    }
                })
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new BaseSubscriber<Items>() {
                    @Override
                    public void onError(NetException.ResponseThrowable e) {
                        listener.onFailure(e.message);
                    }

                    @Override
                    public void onNext(Items items) {
                        listener.onSuccess(items);
                    }
                });

    }

    /**
     * 获取图片列表
     *
     * @param url
     * @param loadingListener
     */
    public static void getImageDetailsUpload(String url, final ImageLoadingListener loadingListener) {
        final ImageList imageList = new ImageList();
        final ArrayList<String> urls = new ArrayList<>();
        HttpRequest.getInstance().getHtml(url)
                .subscribeOn(Schedulers.io())
                .map(new Func1<ResponseBody, String>() {
                    @Override
                    public String call(ResponseBody responseBody) {
                        String html = null;
                        byte[] readByte = readInputStream(responseBody.byteStream());
                        try {
                            html = new String(readByte, "utf-8");
                        } catch (UnsupportedEncodingException e) {
                            e.printStackTrace();
                        }
                        return html;
                    }
                })
                .flatMap(new Func1<String, Observable<Document>>() {
                    @Override
                    public Observable<Document> call(String s) {
                        Document document = Jsoup.parse(s);
                        return Observable.just(document);
                    }
                })
                .map(new Func1<Document, ImageList>() {
                    @Override
                    public ImageList call(Document document) {
                        Element figure = document.getElementsByTag("figure").first();
                        String firstUrl = figure.getElementsByTag("img").first().attr("src");
                        int urlLength = firstUrl.length();
                        String needUrl = firstUrl.substring(0, urlLength - 6);
                        Element pageElement = document.getElementsByClass("prev-next-page").first();
                        String pageText = pageElement.text();
                        int length = pageText.length();
                        int imageNums = Integer.parseInt(pageText.substring(2, length - 1));
                        imageList.setImageNums(imageNums);
                        for (int i = 1; i <= imageNums; i++) {
                            if (i < 10) {
                                urls.add(needUrl + "0" + i + ".jpg");
                            } else {
                                urls.add(needUrl + i + ".jpg");
                            }
                        }
                        imageList.setUrls(urls);
                        return imageList;
                    }
                })
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Action1<ImageList>() {
                    @Override
                    public void call(ImageList imageList) {
                        loadingListener.onSuccess(imageList);
                    }
                });

    }

    /**
     * 解析数据
     *
     * @param url
     * @param listener
     */
    public static void parseTypeUpload(final String url, final ImageInfoListener listener) {
        final ArrayList<DetailInfo> list = new ArrayList<>();
        HttpRequest.getInstance().getHtml(url)
                .subscribeOn(Schedulers.io())
                .map(new Func1<ResponseBody, String>() {
                    @Override
                    public String call(ResponseBody responseBody) {
                        String html = null;
                        byte[] readByte = readInputStream(responseBody.byteStream());
                        try {
                            html = new String(readByte, "utf-8");
                        } catch (UnsupportedEncodingException e) {
                            e.printStackTrace();
                        }
                        return html;
                    }
                })
                .flatMap(new Func1<String, Observable<Document>>() {
                    @Override
                    public Observable<Document> call(String s) {
                        Document document = Jsoup.parse(s);
                        return Observable.just(document);
                    }
                })
                .flatMap(new Func1<Document, Observable<Element>>() {
                    @Override
                    public Observable<Element> call(Document document) {
                        Element content = document.getElementById("content");
                        Elements datas = content.getElementsByTag("article");
                        return Observable.from(datas);
                    }
                })
                .map(new Func1<Element, DetailInfo>() {
                    @Override
                    public DetailInfo call(Element element) {
                        Element title = element.select("a").first();
                        String imageTitle = title.text();
                        String imageId = title.attr("href");
                        Element category = element.select("a").get(1);
                        String imageCategory = category.text();
                        int classId = 0;
                        switch (imageCategory) {
                            case "首页":
                                classId = 1;
                                break;
                            case "性感妹子":
                                classId = 2;
                                break;
                            case "日本妹子":
                                classId = 3;
                                break;
                            case "台湾妹子":
                                classId = 4;
                                break;
                            case "清纯妹子":
                                classId = 5;
                                break;
                            case "妹子自拍":
                                classId = 6;
                                break;
                            case "热门妹子":
                                classId = 7;
                                break;
                            case "推荐妹子":
                                classId = 8;
                                break;

                        }
                        Element date = element.select("span").get(1);
                        String imageDate = date.text();
                        Element times = element.select("span").get(2);
                        String viewTimes = times.text();
                        int leng = viewTimes.length();
                        String viewTi = viewTimes.substring(0, leng - 3).replace(",", "");
                        Element url = element.select("img[data-original]").first();
                        String imageUrl = url.attr("data-original");
                        DetailInfo imageInfo = new DetailInfo();
                        imageInfo.setImageId(imageId);
                        imageInfo.setDescribe(imageTitle);
                        imageInfo.setClassId(classId);
                        imageInfo.setPublishTime(imageDate);
                        imageInfo.setReadCount(Integer.parseInt(viewTi));
                        imageInfo.setUrl(imageUrl);
                        return imageInfo;
                    }
                })
                .map(new Func1<DetailInfo, ArrayList<DetailInfo>>() {
                    @Override
                    public ArrayList<DetailInfo> call(DetailInfo imageInfo) {
                        list.add(imageInfo);
                        return list;
                    }
                })
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Action1<ArrayList<DetailInfo>>() {
                    @Override
                    public void call(ArrayList<DetailInfo> detailInfos) {
                        listener.onSuccess(detailInfos);
                    }
                });
    }

    /**
     * 数据加载监听
     */
    public interface ItemsLoadListener {
        void onStart();

        void onSuccess(Items items);

        void onFailure(String reason);
    }

}
